package au.edu.qut.bpm.genbinder.genetic.crossover;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.uncommons.maths.number.ConstantGenerator;
import org.uncommons.maths.number.NumberGenerator;
import org.uncommons.watchmaker.framework.operators.AbstractCrossover;

import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;

public class LogActivitiesCrossover extends AbstractCrossover<ConcreteEventLog> {
	private boolean performSafetyCheck = true;
	//private int maxNrTries = 50;

	public LogActivitiesCrossover(boolean performSafetyCheck) {
		this(performSafetyCheck, 2);
	}

	public LogActivitiesCrossover(boolean performSafetyCheck, int crossoverPoints) {
		this(performSafetyCheck, new ConstantGenerator<Integer>(crossoverPoints));
	}

	public LogActivitiesCrossover(boolean performSafetyCheck, NumberGenerator<Integer> crossoverPointsVariable) {
		super(crossoverPointsVariable);
		this.performSafetyCheck = performSafetyCheck;
	}

	@Override
	protected List<ConcreteEventLog> mate(ConcreteEventLog parent1, ConcreteEventLog parent2, int numberOfCrossoverPoints, Random rng) {
		ConcreteEventLog offspring1 = parent1.clone();
		ConcreteEventLog offspring2 = parent2.clone();
		
		try {
			

			List<Activity> activities = new ArrayList<Activity>(offspring1.getAbstractLog().getActivities());
			//int nrRestarts = 0;
			//while (true) {
				//boolean safeResult = true;
			int crossoverpoint = rng.nextInt(activities.size() - numberOfCrossoverPoints) + 1;
			
			for (int i = 0; i < numberOfCrossoverPoints; i++) {
				copyBinding(offspring2, offspring1, activities.get(crossoverpoint + i));
				copyBinding(offspring1, offspring2, activities.get(crossoverpoint + i));
			}
				//for (int ncr = 0; ncr < numberOfCrossoverPoints; ncr++) {
					
					
					/*
					if (performSafetyCheck && (!offspring1.isLogSafe() || !offspring2.isLogSafe())) {
						safeResult = false;
						System.out.println("false");
						break;
					}
					*/
				//}
				/*
				if (safeResult || !performSafetyCheck) {
					System.out.println("solution!");
					break; // We've found a solution
				}
				
				nrRestarts++;
				if (nrRestarts > maxNrTries) { // Just give up
					System.out.println("give up");
					offspring1 = parent1.clone();
					offspring2 = parent2.clone();
					break;
				}
				*/
			//}
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		//if safety check true and offsprings are unsafe, return original parents
		if (performSafetyCheck && (!offspring1.isLogSafe() || !offspring2.isLogSafe())) {
			offspring1 = parent1.clone();
			offspring2 = parent2.clone();
		}
		
		List<ConcreteEventLog> result = new ArrayList<ConcreteEventLog>(2);
		result.add(offspring1);
		result.add(offspring2);
		return result;
	}

	private void copyBinding(ConcreteEventLog from, ConcreteEventLog to, Activity activity) {
		to.setActivityResources(activity, from.getActivityResources(activity));
		to.setActivityStart(activity, from.getActivityStart(activity));
	}

}
